﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Security;
using System.Configuration.Provider;
using PagedList;

namespace Ymca.WebSecurity
{
	public class YmcaMembershipProvider: MembershipProvider
	{
		private const int DefaultMaxInvalidPasswordAttempts = 6;
		private const int DefaultMinRequiredNonAlphanumericCharacters = 0;
		private const int DefaultMinRequiredPasswordLength = 7;

		#region MembershipProvider Overrides
		public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
		{
			base.Initialize(name, config);
		}

		public override string ApplicationName { get; set; }

		public override bool ChangePassword(string username, string oldPassword, string newPassword)
		{
			string oldPasswordHash = GeneratePasswordHash(oldPassword);
			string newPasswordHash = GeneratePasswordHash(newPassword);

			using (DataContext dc = new DataContext())
			{
				User user = dc.Users.Find(username);
				if (user != null && user.Password.Equals(oldPasswordHash))
				{
					user.Password = newPasswordHash;
					return true;
				}
				return false;
			}
		}

		public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
		{
			throw new NotImplementedException();
		}

		public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
		{
			string passwordHash = GeneratePasswordHash(password);
			User user = new User()
			{
				UserName = username,
				Password = passwordHash,
				Email = email
			};

			using (DataContext dc = new DataContext())
			{
				if (dc.Users.Find(username) != null)
				{
					status = MembershipCreateStatus.DuplicateUserName;
                    return null;
				}
                if (dc.Users.Where(x => x.Email.Equals(email)).FirstOrDefault() != null)
                {
                    status = MembershipCreateStatus.DuplicateEmail;
                    return null;
                }
				dc.Users.Add(user);
			}
			status = MembershipCreateStatus.Success;

			return new MembershipUser(Name, username, string.Empty, email, passwordQuestion, string.Empty, true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
		}

		public override bool DeleteUser(string username, bool deleteAllRelatedData)
		{
			using (DataContext dc = new DataContext())
			{
				User user = dc.Users.Find(username);
				if (user != null)
				{
					dc.Users.Remove(user);
					return true;
				}
				return false;
			}
		}

		public override bool EnablePasswordReset
		{
			get { return false; }
		}

		public override bool EnablePasswordRetrieval
		{
			get { return false; }
		}

		public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			throw new NotImplementedException();
		}

		public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			
			throw new NotImplementedException();
		}

		public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
		{
			using (DataContext dc = new DataContext())
			{
				int pageNumber = pageIndex != null ? pageIndex : 1;
				int size = pageSize != null ? pageSize : 10;
				IEnumerable<User> users = dc.Users.ToPagedList<User>(pageNumber, size);
				MembershipUserCollection userCollection = ConvertUsersToMembershipUserCollection(users);
				totalRecords = dc.Users.Count();
				return userCollection;
			}
		}

		public override int GetNumberOfUsersOnline()
		{
			throw new NotImplementedException();
		}

		public override string GetPassword(string username, string answer)
		{
			throw new NotImplementedException();
		}

		public override MembershipUser GetUser(string username, bool userIsOnline)
		{
			using (DataContext dc = new DataContext())
			{
				User user = dc.Users.Find(username);
				if (user != null)
				{
					return ConvertUserToMembershipUser(user);
				}
				user = dc.Users.Where(x => x.Email.Equals(username)).FirstOrDefault();
				if (user != null)
				{
					return ConvertUserToMembershipUser(user);
				}
				return null;
			}
		}

		public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
		{
			throw new NotImplementedException();
		}

		public override string GetUserNameByEmail(string email)
		{
			using (DataContext dc = new DataContext())
			{
				User user = dc.Users.Where(x => x.Email.Equals(email)).FirstOrDefault();
				if (user != null)
				{
					return user.UserName;
				}
				return string.Empty;
			}
		}

		public override int MaxInvalidPasswordAttempts
		{
			get { return DefaultMaxInvalidPasswordAttempts; }
		}

		public override int MinRequiredNonAlphanumericCharacters
		{
			get { return DefaultMinRequiredNonAlphanumericCharacters; }
		}

		public override int MinRequiredPasswordLength
		{
			get { return DefaultMinRequiredPasswordLength; }
		}

		public override int PasswordAttemptWindow
		{
			get { throw new NotImplementedException(); }
		}

		public override MembershipPasswordFormat PasswordFormat
		{
			get { throw new NotImplementedException(); }
		}

		public override string PasswordStrengthRegularExpression
		{
			get { throw new NotImplementedException(); }
		}

		public override bool RequiresQuestionAndAnswer
		{
			get { throw new NotImplementedException(); }
		}

		public override bool RequiresUniqueEmail
		{
			get { return true; }
		}

		public override string ResetPassword(string username, string answer)
		{
			throw new NotImplementedException();
		}

		public override bool UnlockUser(string userName)
		{
			throw new NotImplementedException();
		}

		public override void UpdateUser(MembershipUser user)
		{
			throw new NotImplementedException();
		}

		public override bool ValidateUser(string username, string password)
		{
			string passwordHash = GeneratePasswordHash(password);
			using (DataContext dc = new DataContext())
			{
				User user = dc.Users.Find(username);
				if (user != null && user.Password.Equals(passwordHash))
				{
					return true;
				}
				user = dc.Users.Where(x => x.Email.Equals(username)).FirstOrDefault();
				if (user != null && user.Password.Equals(passwordHash))
				{
					return true;
				}
				return false;
			}
		}
		#endregion

		#region Private methods
		public static string GeneratePasswordHash(string password)
		{
			// convert this value to a byte array
			byte[] saltedHashBytes = Encoding.UTF8.GetBytes(password);
			// use hash algorithm to compute the hash
			System.Security.Cryptography.HashAlgorithm algorithm = new System.Security.Cryptography.SHA256Managed();
			// convert merged bytes to a hash as byte array
			byte[] hash = algorithm.ComputeHash(saltedHashBytes);
			// return the has as a base 64 encoded string
			return Convert.ToBase64String(hash);
		}

		private MembershipUser ConvertUserToMembershipUser(User user)
		{
			return new MembershipUser(Name, user.UserName, string.Empty, user.Email, string.Empty, string.Empty, true, false,
									  DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
		}

		private MembershipUserCollection ConvertUsersToMembershipUserCollection(IEnumerable<User> users)
		{
			MembershipUserCollection membershipUserCollection = new MembershipUserCollection();
			foreach (User user in users)
			{
				membershipUserCollection.Add(ConvertUserToMembershipUser(user));
			}
			return membershipUserCollection;
		}
		#endregion
	}
}
